#pragma once

// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license

#include "gl.h"
#include "Selectable.h"
class ShaderProgram;

// ----------------------------------------------------------------------------
// Class "UniformVar"
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


struct UniformVarParams
{
    UniformVarParams(GLenum type);
    UniformVarParams(GLenum type, GLint v); // Sampler
    UniformVarParams(float v);
    UniformVarParams(float a, float b, float c);
    UniformVarParams(float a, float b, float c, float d);
    UniformVarParams(float m[4][4]);


    union 
    {
        GLfloat float_;
        GLfloat float3[3];
        GLfloat float4[4];
        GLfloat floatMat4[4][4];
    } value;
    GLenum type;
};

class UniformVar : public Selectable
{
public:

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    UniformVar(const UniformVarParams& params);


    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    void writeToRenderContext();
    void readFromRenderContext();

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    // 0 if the variable is not made of floats (typically of int or bools)
    size_t getNumFloats() const;
    const GLfloat* getFloats() const;
    void setFloat(size_t i, float newVal);

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    GLenum getType() const;

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    void setValue(const UniformVarParams& params);

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    void setProgram(ShaderProgram* program);
    ShaderProgram* getProgram() const { return program; }

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    const char* getAnsiName() const;
    void setAnsiName(const std::string& newName);
    void setName(const std::wstring& newName) override;

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    void queryValue();

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    static std::string typeToTypeName(GLenum type);

    // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

    bool operator<(const UniformVar& other) const;

private:

    friend std::ostream& operator<<(std::ostream& os, const UniformVar& var);

    void queryLocation() const;

    std::string name; // ansi, unlike Selectable::m_name which is unicode
    ShaderProgram* program;
    mutable GLint location;
    UniformVarParams params;
};


// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

inline bool UniformVar::operator<(const UniformVar& other) const
{
    ASSERT(!name.empty() && !other.name.empty());
    return name < other.name;
}